package cn.wsalix.shiro;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AccountException;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.DisabledAccountException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.ByteSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.anlaser.admin.BaseUser;
import cn.anlaser.utils.BeanMapper;
import cn.wsalix.admin.entity.Permit;
import cn.wsalix.admin.entity.SysRole;
import cn.wsalix.admin.entity.SysUser;
import cn.wsalix.admin.service.RolePermitService;
import cn.wsalix.admin.service.UserRoleService;
import cn.wsalix.admin.service.UserService;
import cn.wsalix.admin.status.UserEnum;
import cn.wsalix.shiro.token.CaptchaToken;
import cn.wsalix.shiro.token.ThirdToken;

public class AuthRealm extends AuthorizingRealm {
	private static final Logger log = LoggerFactory.getLogger(AuthRealm.class);
	// private String adminAccount;
	private UserService userService;
	private UserRoleService userRoleService;
	private RolePermitService rolePermitService;

	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(
			PrincipalCollection principalCollection) {
		log.info("doGetAuthorizationInfo:");
		BaseUser user = (BaseUser) principalCollection.fromRealm(getName())
				.iterator().next();
		if (user == null || user.getId() == null) {
			Subject subject = SecurityUtils.getSubject();
			subject.logout();
		}

		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		if (!user.getRole().equals("admin")) {
			for (SysRole role : userRoleService.findRolesByUserId(user.getId())) {
				info.addRole(role.getCode());
			}
			for (Permit permit : rolePermitService.findPermitsByUserId(user
					.getId())) {
				info.addStringPermission(permit.getCode());
			}
		} else {
			for (SysRole role : userRoleService.findAllRoles()) {
				info.addRole(role.getCode());
			}
			for (Permit permit : rolePermitService.findAllPermits()) {
				info.addStringPermission(permit.getCode());
			}
		}

		return info;
	}

	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(
			AuthenticationToken authenticationToken)
			throws AuthenticationException {
		log.info("doGetAuthenticationInfo:");
		SysUser user = null;
		BaseUser baseUser = null;
		if (authenticationToken instanceof CaptchaToken) {
			CaptchaToken upToken = (CaptchaToken) authenticationToken;
			if (upToken.getUsername() == null) {
				throw new AccountException("No account found");
			}
			if (upToken.getPassword() == null) {
				throw new AccountException("No password found for user ["
						+ upToken.getUsername() + "]");
			}
			user = userService.findByUsername(upToken.getUsername());
			if (user == null) {
				throw new UnknownAccountException("No account found for user ["
						+ upToken.getUsername() + "]");
			}
			if (user.getStatus().ordinal() == UserEnum.lock.ordinal()) {
				throw new LockedAccountException("account Locked for user ["
						+ upToken.getUsername() + "]");
			}
			if (user.getStatus().ordinal() != UserEnum.invocation.ordinal()) {
				throw new DisabledAccountException(
						"account Disabled for user [" + upToken.getUsername()
								+ "]");
			}
			baseUser = BeanMapper.map(user, BaseUser.class);
		} else if (authenticationToken instanceof ThirdToken) {
			ThirdToken upToken = (ThirdToken) authenticationToken;
			user = upToken.getUser();
			baseUser = BeanMapper.map(user, BaseUser.class);
		}
		AuthenticationInfo authInfo = new SimpleAuthenticationInfo(baseUser,
				baseUser.getPassword(), ByteSource.Util.bytes(baseUser
						.getCredentialsSalt()), getName());
		log.info("doGetAuthenticationInfo:" + authInfo);
		return authInfo;
	}

	public UserService getUserService() {
		return userService;
	}

	public void setUserService(UserService userService) {
		this.userService = userService;
	}

	public UserRoleService getUserRoleService() {
		return userRoleService;
	}

	public void setUserRoleService(UserRoleService userRoleService) {
		this.userRoleService = userRoleService;
	}

	public RolePermitService getRolePermitService() {
		return rolePermitService;
	}

	public void setRolePermitService(RolePermitService rolePermitService) {
		this.rolePermitService = rolePermitService;
	}

	@Override
	public void onLogout(PrincipalCollection principals) {
		BaseUser user = (BaseUser) principals.fromRealm(getName()).iterator()
				.next();
		user.setOnlineFlag(false);
		userService.onLogout(user.getId());
		super.onLogout(principals);
	}

}
